package com.origin.oss.specification;

import com.origin.oss.entity.FileInfo;
import com.origin.oss.entity.FileUploadTask;
import com.origin.oss.enums.StorageType;
import com.origin.oss.manager.FileSliceUploadManager;
import com.origin.oss.service.FileInfoService;
import com.origin.oss.service.FileUploadTaskService;
import com.origin.oss.specification.domain.multipart.MultipartFileWrap;
import com.origin.oss.specification.domain.multipart.response.QuickUploadResp;
import com.origin.oss.specification.domain.multipart.request.SliceUploadReq;
import com.origin.oss.specification.domain.multipart.response.CompleteSliceUploadResp;
import com.origin.oss.specification.domain.multipart.response.SliceUploadResp;
import com.origin.oss.specification.domain.object.UploadObjectDomain;
import com.origin.oss.util.concurrent.locks.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.InputStream;

/**
 * @author yezh
 * @date 2024/2/21 16:35
 */
@Slf4j
public class OssClientAdapter implements IOssClient {

    private final IOssClient iOssClient;

    @Autowired
    private FileSliceUploadManager fileSliceUploadManager;

    @Autowired
    private FileInfoService fileInfoService;

    @Autowired
    private FileUploadTaskService fileUploadTaskService;

    @Autowired
    private RedisLock redisLock;

    private static final String FILE_UPLOAD_CHECK = "uploader:file_upload_check:";

    public OssClientAdapter(IOssClient iOssClient) {
        this.iOssClient = iOssClient;
    }

    @Override
    public StorageType getStorageType() {
        return null;
    }

    @Override
    public UploadObjectDomain uploadFile(String fileKey, InputStream is, boolean isOverride) {
        return iOssClient.uploadFile(fileKey, is, isOverride);
    }

    @Override
    public QuickUploadResp quickUpload(String identifier) {
        QuickUploadResp quickUploadResp = new QuickUploadResp();
        FileInfo fileInfo = fileInfoService.getByIdentifier(identifier);
        if (fileInfo != null) {
            quickUploadResp.setFileId(fileInfo.getFileId());
            quickUploadResp.setSkipUpload(true);
            quickUploadResp.setUploaded(getUploadedSlice(identifier));
        }
        return quickUploadResp;
    }

    @Override
    public SliceUploadResp sliceUpload(SliceUploadReq sliceUploadReq) {
        String identifier = sliceUploadReq.getIdentifier();
        int chunkNumber = sliceUploadReq.getChunkNumber();
        SliceUploadResp sliceUploadResp;
        if (fileSliceUploadManager.checkChunkUploaded(identifier, chunkNumber)) {
            log.info("分片已经上传过了, 跳过. identifier: {}, chunkNumber: {}", identifier, chunkNumber);
            sliceUploadResp = new SliceUploadResp();
            sliceUploadResp.setSuccess(true);
        } else {
            MultipartFileWrap qiwenFile = sliceUploadReq.getFile();
            // 检查文件是否有上传过
            checkFileUploaded(sliceUploadReq, qiwenFile);
            // 分片上传记录添加到 redis 中
            fileSliceUploadManager.storeChunkNumber(identifier, chunkNumber);
            // 上传分片
            sliceUploadResp = iOssClient.sliceUpload(sliceUploadReq);
            if (sliceUploadResp.isSuccess()) {
                if (checkSliceUploadComplete(sliceUploadReq)) {
                    completeSliceUpload(sliceUploadReq);
                }
            } else {
                // todo 上传失败, 是否需要自动重试, 还是直接返回
                log.error("文件上传失败, identifier: {}", identifier);
            }
        }
        return sliceUploadResp;
    }

    @Override
    public boolean checkSliceUploadComplete(SliceUploadReq sliceUploadReq) {
        return iOssClient.checkSliceUploadComplete(sliceUploadReq);
    }

    @Override
    public CompleteSliceUploadResp completeSliceUpload(SliceUploadReq sliceUploadReq) {
        return iOssClient.completeSliceUpload(sliceUploadReq);
    }

    @Override
    public void abortSliceUpload(SliceUploadReq sliceUploadReq) {

    }


    private void checkFileUploaded(SliceUploadReq sliceUploadReq, MultipartFileWrap qiwenFile) {
        String identifier = sliceUploadReq.getIdentifier();
        if (!fileSliceUploadManager.checkFileUploaded(identifier)) {
            String key = FILE_UPLOAD_CHECK + identifier;
            if (redisLock.tryLock(key)) {
                try {
                    if (!fileSliceUploadManager.checkFileUploaded(identifier)) {
                        log.info("identifier: {} 首次上传", identifier);
                        // 首次上传, file_info、file_upload_task 添加记录
                        FileInfo fileInfo = FileInfo.init(identifier, qiwenFile.getFileUrl(), qiwenFile.getSize(), getStorageType());
                        // todo 事务
                        fileInfoService.insert(fileInfo);
                        fileUploadTaskService.insertUploadTask(FileUploadTask.init(fileInfo.getFileId(), sliceUploadReq.getTotalChunks()));
                    }
                } finally {
                    redisLock.unlock(key);
                }
            }
        }
    }

}
